package cn.codergege.myspider.component;

import cn.codergege.myspider.scheduler.Scheduler;
import cn.codergege.myspider.utils.MyspiderUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// TODO: 2019-05-30 下载 inputstream 返回给 response?
@Slf4j
public class Downloader implements Runnable {
    private final Scheduler scheduler;
    private final Request request;

    public Downloader(Scheduler scheduler, Request request) {
        this.scheduler = scheduler;
        this.request = request;
    }

    @Override
    public void run() {
        log.info("发起请求 -> [{}]", request.getUrl());

        // TODO: 2019-05-30 client 应该可以定制
        CloseableHttpClient client = HttpClients.createDefault();
        Response response;

        if("get".equalsIgnoreCase(request.getMethod())) { // Get 请求
            response = doGet(scheduler, request, client);
        }

        if("post".equalsIgnoreCase(request.getMethod())) { // Post
            response = doPost(scheduler, request, client);
        }

        log.info("下载完成 -> [{}]", request.getUrl());
    }

    private Response doGet(Scheduler scheduler, Request request, CloseableHttpClient client) {
        Response response = new Response();

        HttpGet httpGet = new HttpGet();

        URI uri = null;
        try {
            URIBuilder uriBuilder= new URIBuilder(request.getUrl());
            if(!MyspiderUtils.isEmpty(request.getNvps())) {
                uri = uriBuilder.addParameters(request.getNvps()).build();
            }
        } catch (URISyntaxException e) {
            log.error("构建请求时出错, {} 不是一个合法的 url.", request.getUrl());
        }
        httpGet.setURI(uri);

        /* // TODO: 2019-05-31 怎么遍历？ 
        for (Map.Entry<String, String> entry: request.getHeaders().entrySet()) {
            httpGet.setHeader(entry.getKey(), entry.getValue());
        }
         */

        // TODO: 2019-05-30 设置 cookie
        CloseableHttpResponse resp = null;
        try {
            resp = client.execute(httpGet);
            int statusCode = resp.getStatusLine().getStatusCode();
            response.setStatusCode(statusCode);
            // TODO: 2019-05-30 301 302 怎么办？
            fillContent(statusCode, response, resp);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("请求出错!");
            response.setStatusCode(-1);
            response.setContent(null);
        } finally {
            if(client != null) {
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return response;
    }

    private Response doPost(Scheduler scheduler, Request request, CloseableHttpClient client) {
        Response response = new Response();

        HttpPost httpPost = new HttpPost(request.getUrl());

        if(!MyspiderUtils.isEmpty(request.getNvps())) {
            try {
                httpPost.setEntity(new UrlEncodedFormEntity(request.getNvps(), request.getCharset()));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                log.error("不符合的表单编码.");
                response.setStatusCode(-1);
                response.setContent(null);
                return response;
            }
        }

        /* // TODO: 2019-05-31 
        for (Map.Entry<String, String> entry: request.getHeaders().entrySet()) {
            httpPost.setHeader(entry.getKey(), entry.getValue());
        }
         */

        CloseableHttpResponse resp = null;
        // TODO: 2019-05-30 cookie
        try {
            resp = client.execute(httpPost);
            int statusCode = resp.getStatusLine().getStatusCode();
            // 放入状态码
            response.setStatusCode(statusCode);
            // 放入返回头
            Map<String, String> headers = new HashMap<>();
            Header[] allHeaders = resp.getAllHeaders();
            for(int i = 0; i < allHeaders.length; i++) {
                headers.put(allHeaders[i].getName(), allHeaders[i].getValue());
            }
            response.setHeaders(headers);
            // 放入 content
            fillContent(statusCode, response, resp);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("请求出错!");
            response.setStatusCode(-1);
        } finally {
            if(client != null) {
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return response;
    }

    private void fillContent(int statusCode, Response response, CloseableHttpResponse resp) throws IOException {
        if(statusCode == 200) {
            HttpEntity entity = resp.getEntity();
            String content = EntityUtils.toString(entity, request.getCharset());
            response.setContent(content);
            EntityUtils.consume(entity);
        } else {
            response.setContent(null);
            log.error("状态码错误!");
        }
    }
}
